/**
 * 需求分析：
 * 1、promise是一个类，表示一个异步操作的最终结果，与之进行交互的方式主要是then
 * 2、创建类的时候传入一个执行器，执行器立即执行
 * 3、必须为三种状态之一：等待态（Pending）、执行态（Fulfilled）和拒绝态（Rejected），初始状态为Pending,状态改变只能为Pending -> Fulfilled；Pending -> Rejected
 * 4、resolve和reject方法是用来改变状态的
 * 5、提供then方法访问其当前值、终值和据因，接受两个参数onFulfilled, onRejected，均为可选参数，分别对promise的成功状态及失败状态进行处理
*/

/**
 * promise状态
*/
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';



class myPromise {
  constructor(init) {
    //捕获执行器错误
    try {
      init(this.resolve, this.reject);
    } catch(e) {
      this.reject(e)
    }
  }

  // 定义promise状态
  status = PENDING;

  // 成功之后的值
  value = undefined;

  // 失败原因
  reason = undefined;

  // 成功回调
  successCallBack = [];

  // 失败回调
  failCallBack = [];

  resolve = value => {
    // 如果状态改变了，则返回
    if(this.status !== PENDING) return;

    // 改变状态为成功
    this.status = FULFILLED;

    // 保存成功之后的值
    this.value = value;

    //判断回调 有则执行
    while(this.successCallback.length) this.successCallback.shift()()
  }

  reject = reason => {
    // 如果状态改变了，则返回
    if(this.status !== PENDING) return;

    // 改变状态为失败
    this.status = REJECTED;

    // 保存失败的原因
    this.reason = reason;

    //判断回调 有则执行
    while(this.failCallback.length) this.failCallback.shift()()
  }

  then(successCallBack, failCallBack) {
    // 参数可选
    successCallBack = successCallBack ? successCallBack : value => value;
    // 参数可选
    failCallBack = failCallBack ? failCallBack : reason => { throw reason };

    //try catch 捕获then回调中的错误
    // then能链式调用，需返回一个新的promise
    let promiseBack = new myPromise((resolve, reject) => {
      // 判断状态
      if(this.status === PENDING) {
        //成功状态
        //settimeout 解决promiseBack undefined错误问题
        setTimeout(() => {
          try {
            let x = successCallback(this.value);
            resolvePromise(promiseBack, x, resolve, reject)
          } catch(e) {
            reject(e);
          }
        }, 0);
      } else if(this.status === REJECTED) {
        //失败状态
        setTimeout(() => {
          try {
            let x = failCallback(this.reason);
            resolvePromise(promiseBack, x, resolve, reject)
          }catch (e) {
            reject(e);
          }
        }, 0)
      } else {
        //等待状态 
        //将成功回调和失败回调存储起来
        //使用函数的形式将回调存起来
        this.successCallBack.push(() => {
          setTimeout(() => {
            try {
              let x = successCallback(this.value);
              resolvePromise(promiseBack, x, resolve, reject)
            } catch(e) {
              reject(e);
            }
          }, 0);
        });

        this.failCallback.push(() => {
          setTimeout(() => {
            try {
              let x = failCallback(this.reason);
              resolvePromise(promiseBack, x, resolve, reject)
            }catch (e) {
              reject(e);
            }
          }, 0)
        });
      }
    })

    return promiseBack;
  }

  /**
   * all
   * 静态方法
  */

  static all(array) {
    let result = [];  //返回的结果
    let index = 0; //结果计数器
    return new MyPromise((resolve, reject) => {
      //如果传入的参数不是数组，则抛出类型错误
      if(array instanceof Array) reject(new TypeError(`Uncaught TypeError: ${array} is not Array`));

      function addData (key, value) {
        result[key] = value;
        index++;
        if (index === array.length) {
          resolve(result);
        }
      }

      for (let i = 0; i < array.length; i++) {
        let current = array[i];
        if (current instanceof MyPromise) {
          // promise 对象
          current.then(value => addData(i, value), reason => reject(reason))
        }else {
          // 普通值
          addData(i, array[i]);
        }
      }
    })
  }

  /**
   * resolve
   * 静态方法
  */
  static resolve(value) {
    if (value instanceof MyPromise) return value;
    return new MyPromise(resolve => resolve(value));
  }

  finally (callback) {
    return this.then(value => {
      return MyPromise.resolve(callback()).then(() => value);
    }, reason => {
      return MyPromise.resolve(callback()).then(() => { throw reason })
    })
  }
  
  catch (failCallback) {
    return this.then(undefined, failCallback)
  }

}

function resolvePromise(promiseBack, x, resolve, reject) {
  /**
   * 1、then可返回promise对象，也可返回普通值
   * 2、如果是普通值 直接调用resolve
   * 3、如果是promise对象 查看promsie对象返回的结果 
   * 4、根据promise结果，决定调用当前promise的resolve还是reject
   * 5、注意：then不能返回promise本身，否则会死循环，得提前规避
  */
  if (promiseBack === x) {
    return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))
  }
  if (x instanceof MyPromise) {
    // promise 对象
    x.then(resolve, reject);
  } else {
    // 普通值
    resolve(x);
  }
}

module.exports = myPromise;
